module Lenguaje where

import Dict

type Value = Int
type FuncId = String
type VarId = String

-- Una expresión del lenguaje es un valor del tipo de datos Exp.

data Op = Add | Sub | Mul
  deriving (Eq,Show) --hacemos deriving Eq solo para facilitar los casos de test

data Exp = Const Value
         | Var VarId
         | BinOp Op Exp Exp
         | IfZero Exp Exp Exp
         | Let VarId Exp Exp
         | Call FuncId [Exp]
         deriving (Eq,Show) --hacemos deriving Eq solo para facilitar los casos de test

-- Un programa es un diccionario de nombres de funciones a
-- sus definiciones.
type ProgramDef = Dict FuncId FuncDef

-- Una función se define mediante los nombres de los
-- parámetros y el cuerpo.
data FuncDef = FuncDef [VarId] Exp
  deriving Show

param :: FuncDef -> [VarId]
param (FuncDef as _) = as

expre :: FuncDef -> Exp
expre (FuncDef _ e) = e


-- *** Ejercicio 2 ***
-- Esta función es un fold para expresiones toma tantas funciones como constructores
-- haya el el tipo de datos expresión y las aplica de manera acorde para la recursión.
foldExp :: (Value -> a) ->
           (VarId -> a) ->
		   (Op -> a -> a -> a) ->
		   ( a -> a -> a -> a) ->
		   (VarId -> a -> a -> a) ->
		   (FuncId -> [a] -> a) ->
		    Exp ->
			a
foldExp f1 f2 f3 f4 f5 f6 (Const v) = f1 v
foldExp f1 f2 f3 f4 f5 f6 (Var v) = f2 v
foldExp f1 f2 f3 f4 f5 f6 (BinOp op e1 e2) = f3 op (foldExp f1 f2 f3 f4 f5 f6 e1) (foldExp f1 f2 f3 f4 f5 f6 e2)
foldExp f1 f2 f3 f4 f5 f6 (IfZero e1 e2 e3) = f4 (foldExp f1 f2 f3 f4 f5 f6 e1) (foldExp f1 f2 f3 f4 f5 f6 e2) (foldExp f1 f2 f3 f4 f5 f6 e3)
foldExp f1 f2 f3 f4 f5 f6 (Let v e1 e2) = f5 v (foldExp f1 f2 f3 f4 f5 f6 e1) (foldExp f1 f2 f3 f4 f5 f6 e2)
foldExp f1 f2 f3 f4 f5 f6 (Call fc le) = f6 fc (foldr ((:).(foldExp f1 f2 f3 f4 f5 f6)) [] le)